package com.zhenwei.zscm.common.utils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

public class Linq {
    /**
     * 从list中获取第一个元素，如果list为null或空，则返回null
     * @param list list
     * @return T
     * @param <T> T
     */
    public static <T> T getFirst(List<T> list) {
        if(list == null || list.isEmpty()){
            return null;
        }
        return list.getFirst();
    }
    /**
     * 从list中获取满足条件的第一个元素，如果list为null或空，则返回null
     * @param list list
     * @param filter 过滤条件
     * @return T
     * @param <T> T
     */
    public static <T> T findFirst(List<T> list, Predicate<T> filter) {
        if(list == null || list.isEmpty()){
            return null;
        }
        return list.stream().filter(filter).findFirst().orElse(null);
    }

    /**
     * 获取第一个元素，如果不存在则返回null，否则按mapper规则转换后返回
     * @param list 源数据
     * @param mapper 转换规则
     * @return T
     * @param <T> T
     * @param <F> F
     */
    public static <T, F> T getFirst(List<F> list, Function<F, T> mapper) {
        if(list == null || list.isEmpty()){
            return null;
        }
        F first = list.getFirst();
        return mapper.apply(first);
    }
    /**
     * 将List<F> 转换为 List<T>
     * @param list 源数据
     * @param mapper 转换方法
     * @return List<T>
     * @param <T> T
     * @param <F> F
     */
    public static <T, F> List<T> mapList(List<F> list, Function<F, T> mapper){
        if(list == null || list.isEmpty()){
            return new ArrayList<>();
        }
        List<T> result = new ArrayList<>();
        list.forEach(x -> {
            var r = mapper.apply(x);
            result.add(r);
        });
        return result;
    }

    /**
     * 检查集合中是否存在满足条件的元素
     * @param list 集合
     * @param predicate 判断表达式
     * @return boolean
     * @param <T> T
     */
    public static <T> boolean exists(List<T> list, Predicate<T> predicate) {
        if(list == null || list.isEmpty()){
            return false;
        }
        return list.stream().anyMatch(predicate);
    }

    /**
     * 检查集合中是否存在指定字段有相同值的对象
     * @param list list
     * @param function 字段
     * @return bool
     * @param <T> T
     * @param <R> R
     */
    public static <T,R> boolean anyRepeat(List<T> list, Function<T, R> function) {
        if(list == null || list.isEmpty()){
            return false;
        }
        Set<R> seenValues = new HashSet<>();

        for (T obj : list) {
            R value = function.apply(obj);
            if (seenValues.contains(value)) {
                return true;
            }
            seenValues.add(value);
        }
        return false;
    }

    /**
     * 过滤list
     * @param list 集合
     * @param predicate 表达式
     * @return List<T>
     * @param <T> T
     */
    public static <T> List<T> filter(List<T> list, Predicate<T> predicate) {
        if(list == null || list.isEmpty()){
            return new ArrayList<>();
        }
        return list.stream().filter(predicate).collect(Collectors.toList());
    }

    public static boolean isEmpty(List<?> list) {
        return list == null || list.isEmpty();
    }

    public static boolean isNotEmpty(List<?> list) {
        return !isEmpty(list);
    }

    public static <T,R> List<R> distinct(List<T> list, Function<T,R> function) {
        if (list == null || list.isEmpty()) {
            return new ArrayList<>();
        }
        return list.stream().map(function).distinct().collect(Collectors.toList());
    }
    public static <T,R> List<R> select(List<T> list, Function<T,R> function){
        if (list == null || list.isEmpty()) {
            return new ArrayList<>();
        }
        return list.stream().map(function).collect(Collectors.toList());
    }
    public static long Sum(List<Integer> list) {
        if(list == null || list.isEmpty()){
            return 0;
        }
        long sum = 0;
        for (Integer integer : list) {
            sum += integer == null ? 0 : integer;
        }
        return sum;
    }
    public static BigDecimal SumOfDecimal(List<BigDecimal> list) {
        if(list == null || list.isEmpty()){
            return BigDecimal.valueOf(0);
        }
        BigDecimal sum = BigDecimal.valueOf(0);
        for (BigDecimal decimal : list) {
            sum = sum.add(decimal).setScale(2, RoundingMode.HALF_UP);
        }
        return sum;
    }
    public static <T> List<T> page(List<T> list, int pageNo, int pageSize) {
        if(Linq.isEmpty(list)){
            return new ArrayList<>();
        }
        return list.stream().skip((long) (pageNo - 1) * pageSize).limit(pageSize).toList();
    }
}
